package com.yourenbang.lingyun.transaction.web.service.impl.pay.withdraw.channel;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayResponse;
import com.alipay.api.domain.AlipayFundTransOrderQueryModel;
import com.alipay.api.domain.AlipayFundTransToaccountTransferModel;
import com.alipay.api.domain.AlipayFundTransUniTransferModel;
import com.alipay.api.domain.Participant;
import com.alipay.api.request.AlipayDataBillBalanceQueryRequest;
import com.alipay.api.request.AlipayFundTransOrderQueryRequest;
import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.response.AlipayDataBillBalanceQueryResponse;
import com.alipay.api.response.AlipayFundTransOrderQueryResponse;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.yourenbang.lingyun.constants.BizCodeMessages;
import com.yourenbang.lingyun.constants.DingDingToken;
import com.yourenbang.lingyun.core.exception.BizRuntimeException;
import com.yourenbang.lingyun.core.exception.UserBizException;
import com.yourenbang.lingyun.core.util.DingdingUtils;
import com.yourenbang.lingyun.core.util.KLog;
import com.yourenbang.lingyun.domain.PayChannel;
import com.yourenbang.lingyun.mapper.PayChannelMapper;
import com.yourenbang.lingyun.transaction.config.DingdingConfig;
import com.yourenbang.lingyun.transaction.exception.WichdrawFailException;
import com.yourenbang.lingyun.transaction.exception.WichdrawWaitException;
import com.yourenbang.lingyun.transaction.mapper.TransactionPayTypeMapper;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.AliFundTransOrderQueryDTO;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.AliFundTransToaccountTransferDTO;
import com.yourenbang.lingyun.transaction.web.service.CommonService;
import com.yourenbang.lingyun.transaction.web.service.impl.pay.withdraw.WithdrawAccountConfig;
import com.yourenbang.lingyun.transaction.web.service.pay.PayTypeService;
import com.yourenbang.lingyun.transaction.web.service.pay.withdraw.channel.AliWithdrawService;
import com.yourenbang.transaction.api.service.pay.PayTypeApiService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Service("aliWithdrawService")
public class AliWithdrawServiceImpl implements AliWithdrawService {

    @Autowired
    private CommonService commonService;
    @Autowired
    private PayTypeService payTypeService;
    @Autowired
    private PayTypeApiService payTypeApiService;
    @Autowired
    private PayChannelMapper payChannelMapper;
    @Autowired
    private DingdingConfig dingdingConfig;
    @Autowired
    private TransactionPayTypeMapper transactionPayTypeMapper;

    /**
     * 单笔转账到支付宝账户(废弃)
     */
    @Deprecated
    @Override
    public AlipayFundTransToaccountTransferResponse aliFundTransToaccountTransfer(AliFundTransToaccountTransferDTO dto) {
        KLog.info("【支付宝账户转账】入参:{}", dto.toJSON());

        AlipayClient alipayClient = payTypeService.getAlipayClientByChannel(dto.getPayChannelId());

        AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();

        AlipayFundTransToaccountTransferModel transferModel = new AlipayFundTransToaccountTransferModel();
        transferModel.setOutBizNo(dto.getOrderNO());
        transferModel.setPayeeType("ALIPAY_LOGONID");
        transferModel.setPayeeAccount(dto.getAliAccount());
        transferModel.setAmount(String.valueOf(dto.getAmount()));
        transferModel.setPayerShowName(WithdrawAccountConfig.formatWithdrawBody(dto.getPlatNo()));
        transferModel.setPayeeRealName(dto.getRealName());

        request.setBizModel(transferModel);

        AlipayFundTransToaccountTransferResponse response = null;
        try {
            KLog.info("【支付宝账户转账】请求参数:{},入参:{}", JSON.toJSONString(request), dto.toJSON());
            response = alipayClient.execute(request);

            if (!response.isSuccess()) {
                KLog.info("【支付宝账户转账】失败,支付宝返回未成功,支付宝返回:{},入参:{}", JSON.toJSONString(response), dto.toJSON());
                //报警
                aliPolicedeal(response);
                throw new WichdrawFailException("【支付宝】" + response.getSubMsg());
            }
            return response;
        } catch (AlipayApiException e) {
            KLog.error("【支付宝账户转账】异常,{},入参:{}", e.getErrMsg(), dto.toJSON(), e);
            throw new BizRuntimeException(BizCodeMessages.UNKNOWN_ERROR, "支付宝转账异常");
        }
    }

    /**
     * 支付宝转账查询
     */
    @Override
    public AlipayFundTransOrderQueryResponse aliFundTransOrderQuery(AliFundTransOrderQueryDTO queryDTO) {
        KLog.info("【支付宝转账查询】入参:{}", queryDTO.toJSON());
        AlipayClient alipayClient = payTypeService.getAlipayClientByChannel(queryDTO.getPayChannelId());
        Map<String, String> typeParam = payTypeApiService.getPayParamsByChannel(queryDTO.getPayChannelId());

        AlipayFundTransOrderQueryRequest request = new AlipayFundTransOrderQueryRequest();

        AlipayFundTransOrderQueryModel queryModel = new AlipayFundTransOrderQueryModel();
        queryModel.setOutBizNo(queryDTO.getOrderNO());

        request.setBizModel(queryModel);

        AlipayFundTransOrderQueryResponse response;
        try {
            KLog.info("【支付宝转账查询】请求参数:{},入参:{}", JSON.toJSONString(request), queryDTO.toJSON());

            if(StringUtils.isBlank(typeParam.get("appCertPath"))) {
                response = alipayClient.execute(request);
            }else {
                response = alipayClient.certificateExecute(request);
            }

            if (!response.isSuccess()) {
                if(StringUtils.equals(response.getSubCode(), "aop.SYSTEM_ERROR")){
                    KLog.info("【支付宝转账查询】处理中, 支付宝返回系统繁忙,支付宝返回:{},入参:{}", JSON.toJSONString(response), queryDTO.toJSON());
                    throw new WichdrawWaitException("支付宝转账查询处理中,"+JSON.toJSONString(response));
                }

                KLog.info("【支付宝转账查询】失败,支付宝返回未成功,支付宝返回:{},入参:{}", JSON.toJSONString(response), queryDTO.toJSON());
                throw new WichdrawFailException("支付宝转账查询失败," + JSON.toJSONString(response));
            }
            return response;
        } catch (AlipayApiException e) {
            KLog.error("【支付宝账户转账查询】异常,{},入参:{}", e.getErrMsg(), queryDTO.toJSON(), e);
            throw new BizRuntimeException(BizCodeMessages.UNKNOWN_ERROR, "支付宝转账查询失败," + e.getMessage());
        }
    }

    /**
     * 单笔转账到支付宝账户(新接口)
     */
    @Override
    public AlipayFundTransUniTransferResponse alipayFundTransUniTransfer(AliFundTransToaccountTransferDTO dto) {
        KLog.info("【支付宝账户转账(新接口)】入参:{}", dto.toJSON());

        AlipayDataBillBalanceQueryResponse alipayDataBillBalanceQueryResponse
                = alipayDataBillBalanceQuery(dto.getPayChannelId());

        if (Objects.isNull(alipayDataBillBalanceQueryResponse)){
            KLog.error("查询支付宝商家账户当前余额查询返回空，payChannelId={}",dto.getPayChannelId());
            throw new WichdrawFailException("通道维护中,请稍后再试");
        }

        BigDecimal availableAmount = new BigDecimal(alipayDataBillBalanceQueryResponse.getAvailableAmount());
        if (availableAmount.compareTo(dto.getAmount()) < 0) {
            PayChannel payChannel = payChannelMapper.selectByPrimaryKey(dto.getPayChannelId());

            String msg = "【账户余额不足预警】" + payChannel.getName() + " 账户仅剩[" + availableAmount + "]元,请尽快充值!";
            DingdingUtils.sendToDingding(msg, dingdingConfig.getDingdingWarnToken());
            //关闭支付方式
            transactionPayTypeMapper.closePayTypeByChannelId(dto.getPayChannelId());
            String message = "【账户余额不足预警】已关闭支付渠道:" + payChannel.getName();
            DingdingUtils.sendToDingding(message, dingdingConfig.getDingdingWarnToken());
            throw new WichdrawFailException("通道维护中,请稍后再试");
        }

        AlipayClient alipayClient = payTypeService.getAlipayClientByChannel(dto.getPayChannelId());

        AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();

        AlipayFundTransUniTransferModel transferModel = new AlipayFundTransUniTransferModel();
        transferModel.setOutBizNo(dto.getOrderNO());
        transferModel.setProductCode("TRANS_ACCOUNT_NO_PWD");
        transferModel.setBizScene("DIRECT_TRANSFER");
        transferModel.setTransAmount(String.valueOf(dto.getAmount()));
        transferModel.setOrderTitle(WithdrawAccountConfig.formatWithdrawBody(dto.getPlatNo()));

        Participant payeeInfo = new Participant();
        payeeInfo.setIdentity(dto.getAliAccount());
        payeeInfo.setName(dto.getRealName());
        payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
        transferModel.setPayeeInfo(payeeInfo);

        request.setBizModel(transferModel);

        AlipayFundTransUniTransferResponse response = null;
        try {
            KLog.info("【支付宝账户转账(新接口)】请求参数:{},入参:{}", JSON.toJSONString(request), dto.toJSON());
            response = alipayClient.certificateExecute(request);

            if (!response.isSuccess()) {
                KLog.info("【支付宝账户转账(新接口)】失败,支付宝返回未成功,支付宝返回:{},入参:{}", JSON.toJSONString(response), dto.toJSON());
                //报警
                aliPolicedeal(response);
                throw new WichdrawFailException("【支付宝】" + response.getSubMsg());
            }
            return response;
        } catch (AlipayApiException e) {
            KLog.error("【支付宝账户转账(新接口)】异常,{},入参:{}", e.getErrMsg(), dto.toJSON(), e);
            throw new BizRuntimeException(BizCodeMessages.UNKNOWN_ERROR, "支付宝转账异常");
        }
    }

    /**
     * 支付宝商家账户当前余额查询
     */
    @Override
    public AlipayDataBillBalanceQueryResponse alipayDataBillBalanceQuery(Integer payChannelId) {

        LocalDateTime queryTime = LocalDateTime.now();
        AlipayClient alipayClient = payTypeService.getAlipayClientByChannel(payChannelId);
        AlipayDataBillBalanceQueryRequest request = new AlipayDataBillBalanceQueryRequest();
        AlipayDataBillBalanceQueryResponse response = null;
        try {
            KLog.info("【支付宝商家账户当前余额查询】请求参数:{},入参:{},查询时间:{}", JSON.toJSONString(request),
                    payChannelId,queryTime);
            response = alipayClient.certificateExecute(request);
            if (!response.isSuccess()) {
                KLog.info("【支付宝商家账户当前余额查询】失败,支付宝返回未成功,支付宝返回:{},入参:{},查询时间:{}",
                        JSON.toJSONString(response), payChannelId,queryTime);
                throw new UserBizException(BizCodeMessages.UNKNOWN_ERROR,"【支付宝】" + response.getSubMsg());
            }
        } catch (AlipayApiException e) {
            KLog.error("【支付宝商家账户当前余额查询】异常,{},入参:{},查询时间:{}", e.getErrMsg(), payChannelId,queryTime);
            throw new BizRuntimeException(BizCodeMessages.UNKNOWN_ERROR, e.getErrMsg());
        }
        KLog.info("【支付宝商家账户当前余额查询】成功,支付宝返回:{}",JSON.toJSONString(response));
        return response;
    }

    /**
     * 支付宝 转账 报警
     */
    private void aliPolicedeal(AlipayResponse response){
        if(StringUtils.equalsAny(response.getSubCode(), "PAYER_BALANCE_NOT_ENOUGH",
                "EXCEED_LIMIT_DM_MAX_AMOUNT","PAYCARD_UNABLE_PAYMENT","BALANCE_IS_NOT_ENOUGH")){  //付款方余额不足 超过单日最大转账额度 付款账户余额支付功能不可用

            Map<String, String> aliParams = response.getParams();
            if(aliParams==null){
                aliParams = new HashMap<>();
            }
            String msg = "【支付宝-提现】"+response.getSubMsg() +"\n" +
                    aliParams.get("biz_content") +"\n" +
                    LocalDateTime.now();
            if(commonService.isProd()) {
                DingdingUtils.sendToDingding(msg, DingDingToken.POLICE);
            }else {
                DingdingUtils.sendToDingding(msg, DingDingToken.TEST);
            }
            throw new WichdrawFailException("【支付宝】通道维护中,请稍后再试");
        }
    }
}
